// Controller.m
// By Jayson Adams
// NeXT Strategic Developer Engineer
//
// You may freely copy, distribute and reuse the code in this example.
// NeXT disclaims any warranty of any kind, expressed or implied, as to its
// fitness for any particular use.

#import <libc.h>			// for strcmp(), index(), rindex()
#import <streams/streams.h>
#import <appkit/publicWraps.h>		// for NXConvertWinNumToGlobal()
#import <appkit/Control.h>
#import <appkit/NXImage.h>
#import <appkit/ScrollView.h>
#import <appkit/Text.h>
#import <appkit/Listener.h>
#import <appkit/Speaker.h>
#import <appkit/Window.h>
#import <appkit/OpenPanel.h>
#import <appkit/SavePanel.h>
#import <appkit/Application.h>

#import "CopyIcon.h"
#import "FileImage.h"
#import "GraphicImage.h"

#import "Controller.h"


@implementation Controller


/* instance methods */

- appDidInit:sender
{
    [Text registerDirective:"FileImage" forClass:[FileImage class]];
    [Text registerDirective:"GraphicImage" forClass:[GraphicImage class]];
    
    [self registerWindow];
    
    [textObj setSel:0 :0];
    
    return self;
}

- registerWindow
{
    unsigned int	windowNum;
    id			speaker;
    
  /* register our app icon window with the workspace */
    NXConvertWinNumToGlobal([[textObj window] windowNum], &windowNum);
    speaker = [NXApp appSpeaker];
    [speaker setSendPort:NXPortFromName(NX_WORKSPACEREQUEST, NULL)];
    [speaker registerWindow:windowNum
    	     toPort:[[NXApp appListener] listenPort]];

    return self;
}

static BOOL isEPSOrTIFF(char *filePath)
{
    char	*extension;
    
    if (!(extension = rindex(filePath, '.'))) {
        return NO;
    }
    return (!strcmp(".eps", extension) || !strcmp(".tiff", extension));
}

- (int)iconEntered:(int)windowNum at:(double)x :(double)y
    iconWindow:(int)iconWindowNum iconX:(double)iconX iconY:(double)iconY
    iconWidth:(double)iconWidth iconHeight:(double)iconHeight
    pathList:(char *)pathList
{
    char	*stringPosition;
    int		files=1;
    id		newImage, newGraphic;
    NXSize	size = {48.0, 48.0};
    struct stat statData;
        
  /* the number of tabs + 1 equals the number of files dragged in */
    stringPosition = pathList;
    while (stringPosition = index(stringPosition, '\t')) {
        files++;
        stringPosition++;
    }
    
  /* make sure the user dragged one file in (and it wasn't root) */
    if ((files > 1) || !(*pathList)) {
	acceptedIcon = NO;
	return 0;
    }
    
  /* punt if a directory */
    stat(pathList, &statData);
    if (statData.st_mode & S_IFDIR) {
        acceptedIcon = NO;
	return 0;
    }
    
    acceptedIcon = YES;
    
    if (isEPSOrTIFF(pathList)) {
      /* copy the tiff or eps image into the text object */
	newImage = [[NXImage alloc] initFromFile:pathList];
	newGraphic = [[GraphicImage alloc] initForImage:newImage];
	[textObj replaceSelWithCell:newGraphic];
    } else {
     /*
      * use some PostScript code to copy the bits from the Workspace
      * window into our NXImage
      */
	newImage = [[NXImage alloc] initSize:&size];
	if ([newImage lockFocus]) {
	    copyIconPicture(iconWindowNum, iconX, iconY, iconWidth,
	    		    iconHeight);
	    [newImage unlockFocus];
	    newGraphic = [[FileImage alloc] initForImage:newImage
	    				 fileName:pathList];
	    [textObj replaceSelWithCell:newGraphic];
	}
    }
    
    return 0;
}

- (int)iconExitedAt:(double)x :(double)y
{
    NXSelPt	start, end;
    
    if (acceptedIcon) {
	[[textObj getSel:&start :&end] setSel:start.cp - 1 :start.cp];
	[textObj replaceSel:""];
    }
    
    return 0;
}

- (int)iconReleasedAt:(double)x :(double)y ok:(int *)flag
{
    if (acceptedIcon) {
        *flag = 1;
    } else {
    	*flag = 0;
    }

    return 0;
}

- lipService:sender
{
    id		uniqueLipImage, lips;
    
  /* 
   * we could use findImageNamed: to get the image, but it always returns the
   * same instance for a given name.  This causes problems when we have two
   * graphicImages using the lips icon 'cause when they get freed, they both
   * free the same nximage (and the app crashes).  We can't do something like
   * [[NXImage findImageNamed:"lips"] copy] 'cause the copy method only
   * duplicates the nximage, not any of its representations.  Using 
   * initFromSection: is a reasonable workaround.
   */
    uniqueLipImage = [[NXImage alloc] initFromSection:"lips.tiff"];
    
    lips = [[GraphicImage alloc] initForImage:uniqueLipImage];
    [textObj replaceSelWithCell:lips];
    
    return self;
}

#define OPEN 1
#define OPEN_RTF_AS_ASCII 2

- open:sender
{
    id		openPanel;
    NXStream	*stream;
    const char	*types[2] = {"rtf", NULL};
    
    openPanel = [OpenPanel new];
    [openPanel allowMultipleFiles:NO];
    
    if ([openPanel runModalForTypes:types]) {
	stream = NXMapFile([openPanel filename], NX_READONLY);
	if ([[sender selectedCell] tag] == OPEN_RTF_AS_ASCII) {
	    [textObj readText:stream];
	} else {
	    [textObj readRichText:stream];
	}
	NXCloseMemory(stream, NX_FREEBUFFER);
	[textObj setSel:0 :0];
    }
    
    return self;
}

- save:sender
{
    id		savePanel;
    NXStream	*stream;
    
    savePanel = [SavePanel new];
    [savePanel setRequiredFileType:"rtf"];
    
    if ([savePanel runModal]) {
        stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
	[textObj writeRichText:stream];
	if (NXSaveToFile(stream, [savePanel filename]) == -1) {
	    NXRunAlertPanel(NULL, "Couldn't write file", NULL, NULL, NULL);
	}
	NXCloseMemory(stream, NX_FREEBUFFER);
    }
    
    return self;
}

- windowWillResize:sender toSize:(NXSize *)frameSize
{
    if (frameSize->height < 200.0) {
        frameSize->height = 200.0;
    }
    
    if (frameSize->width < 200.0) {
        frameSize->width = 200.0;
    }
    return self;
}

- info:sender
{
    if (!infoPanel) {
        [NXApp loadNibSection:"Info.nib" owner:self];
    }
    
    [infoPanel makeKeyAndOrderFront:NULL];
    
    return self;
}


/* outlet initialization */

- setScrollView:anObject
{
    scrollView = anObject;
    textObj = [scrollView docView];
    return self;
}

@end